package com.fzkj.juc.completablefuture;


import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @DESCRIPTION 移步编排 测试
 * @Author yaya
 * @DATE 2022/7/24
 */
public class CompletableTest {

    private static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        useRunAsyncStartAThread();
//        useSupplyAsyncStartAThread();
//        useSupplyAsyncStartAThreadAndComplete(); // 使用 whenComplete & exceptionally 处理上一个线程执行结果
//        useSupplyAsyncStartAThreadAndHandle(); // 使用handle方法处理上一个线程的执行结果
//        multiTaskThread_runAfterBoth();
//        multiTaskThread_thenAcceptBothAsync();
//        multiTaskThread_thenCombineAsync();
        multiTaskThread_allOf();
    }

    public static void useRunAsyncStartAThread(){
        System.out.println("线程开始...");
        CompletableFuture.runAsync(() -> {
            int i = 10 / 2;
            System.out.println(i);
        }, executor);
        System.out.println("线程结束...");
    }

    public static void useSupplyAsyncStartAThread() throws ExecutionException, InterruptedException {
        System.out.println("线程开始...");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        System.out.println("线程结束...");
        System.out.println("线程执行结果是 -> " + future.get());
    }

    public static void useSupplyAsyncStartAThreadAndComplete() throws ExecutionException, InterruptedException {
        System.out.println("线程开始...");
        CompletableFuture.supplyAsync(() -> {
            int i = 10 / 0;
            return i;
        }, executor).whenComplete((res, exception) -> {
            System.out.println("执行结果是 -> " + res + "  执行异常是 -> " + exception);
        }).exceptionally((e) -> {
            return 20;  // 这个结果会在线程执行异常时覆盖掉supplyAsync中的返回值
        });
    }

    public static void useSupplyAsyncStartAThreadAndHandle() throws ExecutionException, InterruptedException {
        System.out.println("线程开始...");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor).handle((res, e) -> {
            if (res != null) {
                return res;
            }
            if (e != null) {
                System.out.println(e);
                return 11;
            }
            return 0;
        });
        System.out.println("最终结果 -> " + future.get());
    }

    // 串行化测试demo
    public static void threadSerial(){
        /**
         * 1、thenRun、thenRunAsync 不会接收上一个线程执行结果作为参数、不会有返回
         * 2、.thenAcceptAsync/.thenAccept(res -> {
         *      }): 可以接收上一个线程执行结果作为参数，但不会有返回值
         * 3、thenApply/.thenApplyAsync(res -> {
         *             return 1;
         *         }); : 可以接收上一个线程执行结果作为参数，而且会有返回值
         */
        CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor).thenApplyAsync(res -> {
            return 1;
        });
    }

    // 多任务组合测试demo【都完成】
    /**
     * runAfterBoth/runAfterBothAsync: future1和future2执行结束后执行新线程中的，不能接收future2和future1的执行结果作为参数。也不能有返回值
     */
    public static void multiTaskThread_runAfterBoth(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.runAfterBoth(future2, () -> {
            try {
                System.out.println(future1.get());
                System.out.println(future2.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            System.out.println("world");
        });
    }

    // 多任务组合测试demo【都完成】
    /**
     * thenAcceptBoth/thenAcceptBothAsync: future1和future2执行结束后执行新线程中的，可以接收future2和future1的执行结果作为参数。但不能有返回值
     */
    public static void multiTaskThread_thenAcceptBothAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.thenAcceptBothAsync(future2, (res, res1) -> {
            System.out.println(res + " -> " + res1 + " -> world");
        });
    }

    // 多任务组合测试demo【都完成】
    /**
     * thenCombine/thenCombineAsync: future1和future2执行结束后执行新线程中的，可以接收future2和future1的执行结果作为参数。也可以有返回值
     */
    public static void multiTaskThread_thenCombineAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        CompletableFuture<String> result = future1.thenCombineAsync(future2, (res, res1) -> {
            return res + " -> " + res1 + " -> world";
        }, executor);
        System.out.println(result.get());
    }

    // 多任务组合测试demo【一个完成】
    /**
     * runAfterEitherAsync/runAfterEither：其中组合执行线程中一个线程执行结束就执行后面的线程。不能接收参数，也没有返回值
     */
    public static void multiTaskThread_runAfterEitherAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.runAfterEitherAsync(future2, () -> {
            System.out.println("world");
        });
    }

    // 多任务组合测试demo【一个完成】
    /**
     * acceptEitherAsync/acceptEither：其中组合执行线程中一个线程执行结束就执行后面的线程【这几个线程的返回值类型必须相同】。能接收参数，但是没有返回值
     */
    public static void multiTaskThread_acceptEitherAsync(){
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.acceptEitherAsync(future2, (res) -> {
            System.out.println("world");
        });
    }

    // 多任务组合测试demo【一个完成】
    /**
     * applyToEitherAsync/applyToEither: 其中组合执行线程中一个线程执行结束就执行后面的线程【这几个线程的返回值类型必须相同】。能接收参数，也有返回值
     */
    public static void multiTaskThread_applyToEitherAsync(){
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.applyToEitherAsync(future2, (res) -> {
            return "world";
        });
    }

    // 多任务组合 【等待所有组合的线程执行结束】
    public static void multiTaskThread_allOf() throws ExecutionException, InterruptedException {
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        CompletableFuture<Void> future = CompletableFuture.allOf(future1, future2);
        future.get(); // 等待future1和future2执行结束
        /**
         * 注意：CompletableFuture.allOf返回的future.get并不能获取到future1或者 future2的执行结果
         * 要获取future1或者future2的执行结果还是需要调用各自的get方法
         */
        System.out.println(future1.get());
        System.out.println(future2.get());
    }

    // 多任务组合 【等待所有组合的线程中一个执行结束】
    public static void multiTaskThread_anyOf() throws ExecutionException, InterruptedException {
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        CompletableFuture<Object> future = CompletableFuture.anyOf(future1, future2);
        future.get(); // 等待future1和future2执行结束
        /**
         * 注意：CompletableFuture.anyOf返回的future.get只能获取成功线程的返回值
         */
        System.out.println(future1.get());
        System.out.println(future2.get());
    }

}
